package address;

import utils.Base58;
import utils.Hash;

import java.security.*;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECPoint;
import java.util.Arrays;

/**
 * @authro:liuxiancai
 * @enmail:2791841851@qq.com
 * @desc: 该类用于推到生成原始比特币地址
 * @datetime:2021/12/20 14:28
 */
public class Address {

    /**
     * 该方法用于生成一堆随机密钥，并将生成的密钥对返回
     * @return 生成的对象
     */
    public KeyPair genrateKeys() {
        try {
            KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
            ECGenParameterSpec spec = new ECGenParameterSpec("secp256k1");
            generator.initialize(spec);
            return generator.generateKeyPair();

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     *   该方法根据给定的密钥数据，推到生成对应的原始格式的比特币地址
     * @param "KeyPair" 生成的密钥对
     * @return 推到生成的比特币地址
     *   */
    public String newAddress(KeyPair keyPair){
        ECPublicKey publicKey = (ECPublicKey) keyPair.getPublic();
        ECPoint point = publicKey.getW();
        //原始格式的公钥
        byte[]  pubKey = toUncompressPubKey(point);

        //对公钥进行哈希计算
        byte[] pubKeyHash256 = Hash.SHA256(pubKey);
        byte[] pubHash = Hash.RIPEMD160(pubKeyHash256);

        byte[] version = new byte[1];
        version[0] = 0x00;

        byte[] var_pubhash = new byte[version.length + pubHash.length];
        System.arraycopy(version,0,var_pubhash,0,version.length);
        System.arraycopy(pubHash,0,var_pubhash,1,pubHash.length);

        //双哈希，取前4个字节
        byte[] hash1 = Hash.SHA256(var_pubhash);
        byte[] hash2 = Hash.SHA256(hash1);
        byte[] chaeck = new byte[4];
        System.arraycopy(hash2,0,chaeck,0,chaeck.length);

        byte[] var_pubhash_check = new byte[var_pubhash.length + chaeck.length];
        System.arraycopy(var_pubhash,0,var_pubhash_check,0,var_pubhash.length);
        System.arraycopy(chaeck,0,var_pubhash_check,var_pubhash.length,chaeck.length);

        //对拼接的字节数组进行baes58编码
        return Base58.encode(var_pubhash_check);

    }
    /**校验比特币地址是否合规范，并返回结果
     * addr 要校验的字符串
     * return true表示符合
     * **/
    public boolean validateAdder(String addr){


        if("".equals(addr)||addr  == null){
            return false;
        }
        byte[] var_pubhash_check = Base58.decode(addr);
        if(var_pubhash_check.length<4){
            return false;
        }
        byte[] check = new byte[4];
        System.arraycopy(var_pubhash_check,var_pubhash_check.length-4,check,0,4);



        byte[] ver_pubhash = new byte[var_pubhash_check.length - 4];
        System.arraycopy(var_pubhash_check,0,ver_pubhash,0,ver_pubhash.length);

        //双hash,取前4个字节
        byte[] hash1 = Hash.SHA256(ver_pubhash);
        byte[] hash2 = Hash.SHA256(hash1);

        if(hash2 == null){
            return false;
        }
        byte[] check_sum = new byte[4];
        System.arraycopy(hash2,0,check_sum,0,check_sum.length);


        //比较两个字节数组是否相等


        return Arrays.equals(check, check_sum);
    }



    /**
     * 该方法用于生成非压缩格式
     *
     * */

    public static byte[] toUncompressPubKey(ECPoint point){
        byte[] xBytes = point.getAffineX().toByteArray();
        byte[] yBytes = point.getAffineY().toByteArray();

        //原始格式：04 + x坐标 + y坐标 = 65字节
        byte[] pubKey = new byte[1+2*32];
        pubKey[0] = 04;
        //x坐标
        if(xBytes.length == 32){
            //通过拷贝来完成数组的拼接
            System.arraycopy(xBytes,0,pubKey,1,xBytes.length);
        }else if(xBytes.length > 32){
            //只取后3位
            System.arraycopy(xBytes,1,pubKey,1,32);
        }
        //y坐标
        if (yBytes.length == 32){
            System.arraycopy(yBytes,0,pubKey,33,yBytes.length);
        }else if(yBytes.length > 32){
            System.arraycopy(yBytes,1,pubKey,33,32);
        }

        return pubKey;
    }


}